package trader.currency.concurrent;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.locks.ReentrantLock;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import trader.util.Util;

public class Poller implements Runnable {
    private static final String REPLACE_ME = "@@@";
    private static final String SEARCH_URL = "/search.php?market=CURRENCY&underlying=" + REPLACE_ME + "/SEK&instrument_type=MiniFuture";
    public static ReentrantLock lock = new ReentrantLock();
    
    private static String data_key;
    private final Instrument instrument;
    private final Currency currency;
    
    public Poller(String id, Currency currency) {
        instrument = new Instrument(id);
        this.currency = currency;
        //this.data_key = data_key;
    }
    
    @Override
    public void run() {
        System.out.println("Poller " + instrument.id + " starting");
        getDataKey();
        while (true) {
            try {
            lock.lock();
                //getDataKey();
                updatePrice();
                logic();
            } finally {
                lock.unlock();
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }
    
    private void updatePrice() {
        URL url = null;
        try {
            url = new URL(Util.BASE_URL + "/scripts/php/data/getdata.php");
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return;
        }
        try {
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            String data = "action=data_by_id&id=" + instrument.id + "&data_key=" + data_key;
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Cookie", Util.sessionId);
            conn.setDoOutput(true);
            OutputStream out = conn.getOutputStream();
            out.write(data.getBytes());
            out.close();
            String line = "";
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            while ((line = in.readLine()) != null) {
                System.out.println(instrument.id + ": " + line);
                Object obj = Util.fromJSon(line);
                if (obj instanceof JSONObject) {
                    data_key = (String)((JSONObject)obj).get("data_key");
                    Object instrObj = ((JSONObject)obj).get("instruments");
                    if (instrObj instanceof JSONArray) {
                        JSONArray instruments = (JSONArray)instrObj;
                        if (instruments.isEmpty()) {
                            continue;
                        }
                        if (instruments.size() != 1) {
                            System.out.println(instrument.id + ": Longer than 1: " + instruments);
                        }
                        JSONObject instr = (JSONObject)instruments.get(0);
                        instrument.prevPrice = instrument.currPrice;
                        if (instr.get("ask") instanceof Long) {
                            instrument.currPrice = (double)(Long)instr.get("ask");
                        } else if (instr.get("ask") instanceof Double) {
                            instrument.currPrice = (Double)instr.get("ask");
                        }
                    }
                }
            }
            in.close();
        } catch (IOException e) {
            System.out.println("Poller " + instrument.id + ": " + e);
        }
    }
    
    private void logic() {
        if (instrument.prevPrice == 0 || instrument.currPrice == 0) {
            return;
        }
        
        double diff = (instrument.prevPrice - instrument.currPrice) / instrument.prevPrice;
        
        //if (iter++ % 60 == 0) {
        //    System.out.println(instrument.id + " currPrice=" + instrument.currPrice + ", prevPrice=" + instrument.prevPrice + ", diff=" + diff);
        //}
        
        if (diff > Util.buyLimit) {
            long cash = Util.atomicCash.get();
            if (cash < instrument.currPrice) {
                return;
            }
            int volume = (int)(cash / instrument.currPrice);
            if (Util.busy.getAndSet(true)) {
                System.out.println("Found (but already busy) " + instrument.id + ", currPrice=" + instrument.currPrice + ", prevPrice=" + instrument.prevPrice + ", diff=" + diff);
                return;
            }
            Util.buy(instrument.id, instrument.currPrice, volume, Util.buyPortfolio);
            Util.cashChanged.set(true);
            instrument.volume = volume;
            if (instrument.internalId == null) {
                instrument.internalId = getInternalId(instrument.id, Util.buyPortfolio);
            }
            System.out.println("Bought " + instrument.id + ", volume=" + volume + ", price=" + instrument.currPrice + ", prevPrice=" + instrument.prevPrice + ", diff=" + diff);
            getRidOf();
        } else if (diff > Util.buyLimit / 4) {
            System.out.println(instrument.id + ": prev=" + instrument.prevPrice + ", curr=" + instrument.currPrice + ", diff=" + diff);
        }
    }
    
    private void getRidOf() {
        int i = 0;
        while (true) {
            updatePrice();
            
            double diff = (instrument.currPrice - instrument.prevPrice) / instrument.prevPrice;
            
            if (diff > Util.buyLimit * 0.75) {
                Util.sell(instrument.id, instrument.internalId, instrument.currPrice, instrument.volume);
                System.out.println("Sold " + instrument.id + ", volume=" + instrument.volume + ", price=" + instrument.currPrice + ", prevPrice=" + instrument.prevPrice + ", diff=" + diff);
                Util.busy.set(false);
                return;
            }
            
            i++;
            if (i > 10) {
                System.out.println("Warning: " + instrument.id + " " + i + " (>10) iterations since buy");
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }
    
    private String getInternalId(String id, int portfolio) {
        try {
            URL url = new URL(Util.BASE_URL + "/scripts/php/data/getdata.php");
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            String data = "action=get_portfolio_content&portfolio_id=" + portfolio;
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Cookie", Util.sessionId);
            conn.setDoOutput(true);
            OutputStream out = conn.getOutputStream();
            out.write(data.getBytes());
            out.close();
            String line = "";
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            while ((line = in.readLine()) != null) {
                if (line.equals("")) {
                    continue;
                }
                Object obj = Util.fromJSon(line);
                if (obj instanceof JSONObject) {
                    JSONObject jsonObj = (JSONObject)obj;
                    JSONObject content = (JSONObject)jsonObj.get("content");
                    for (Object o : content.keySet()) {
                        JSONObject jsonInstr = (JSONObject)content.get(o);
                        String rid = (String)jsonInstr.get("instrument_id");
                        if (rid.equals(id)) {
                            return (String)o;
                        }
                    }
                } else if (obj instanceof JSONArray) {
                    //Nothing in portfolio
                } else {
                    System.out.println("What is this? " + obj.getClass() + " : line");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(0);
        }
        return null;
    }
    
    private void getDataKey() {
        URL url = null;
        try {
            url = new URL(Util.BASE_URL + SEARCH_URL.replaceAll(REPLACE_ME, currency.name));
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return;
        }
        try {
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Cookie", Util.sessionId);
            String line = "";
            String magic = "option = { action: 'data_by_id', data_key: ";
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            while ((line = in.readLine()) != null) {
                line = line.trim();
                if (line.startsWith(magic)) {
                    data_key = line.substring(line.indexOf("'", magic.length()) + 1, line.lastIndexOf("'"));
                    break;
                }
            }
            in.close();
        } catch (IOException e) {
            System.out.println("getDataKey() failed: " + currency.name + " " + e);
        }
    }
}
